package com.xunk.gateway.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xunk.common.core.constant.Constants;
import com.xunk.common.core.exception.CaptchaException;
import com.xunk.common.core.utils.*;
import com.xunk.common.core.web.domain.AjaxResult;
import com.xunk.common.redis.service.RedisService;
import com.xunk.gateway.filter.ValidateCodeFilter;
import com.xunk.gateway.service.CodeService;
import com.xunk.system.api.RemoteUserService;
import com.xunk.system.api.domain.SysUser;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.server.ServerRequest;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

/**
 * 手机验证码实现处理
 *
 * @author ruoyi
 */
@Service("authCodeService")
@Slf4j
@RefreshScope
public class AuthCodeServiceImpl implements CodeService {
    @Autowired
    private RedisService redisService;

    @Autowired
    PasswordEncoder passwordEncoder;
    //
    @Autowired
    RemoteUserService userService;

    @Value("${sms.domain}")
    private String smsDomain;

    @Value("${sms.platformId}")
    private String smsPlatformId;

    @Value("${sms.key}")
    private String smsKey;

    private static final String smsUrl = "/estate-manager/admin/open_api/send/sms";


    Pattern pattern = Pattern.compile("^(13[0-9]|14[5|7]|15[0|1|2|3|4|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\\d{8}$");

    @Resource(name = "validateCodeService")
    CodeService validateCodeService;

    /**
     * 生成验证码
     */
    @Override
    public AjaxResult createCapcha(ServerRequest serverRequest) throws IOException, CaptchaException {
        // 先校验图片验证码是否正确
//        validateCodeService.checkCapcha(serverRequest.queryParam(ValidateCodeFilter.CODE).orElse(""), serverRequest.queryParam(ValidateCodeFilter.UUID).orElse(""));
        // 验证手机号格式是否正确
        String phone = serverRequest.queryParam("username").orElse("");
        if (!pattern.matcher(phone).matches()) {
            throw new CaptchaException("手机号格式不正确");
        }
        String frequency = Constants.USER_LOGIN_FREQUENCY + phone;
        String isFrequency = redisService.getCacheObject(frequency);
        if (DataUtils.isNotEmpty(isFrequency)) {
            throw new CaptchaException("发送验证码太频繁，稍等片刻~");
        }

        // 自动帮助用户注册一个账号
        AjaxResult result = userService.autoRegister(new SysUser(phone, IdUtils.generateId()));
        if (result == null || (!result.isSuccess() && !result.getMsg().contains("登录账号已存在"))) {
            throw new CaptchaException("用户生成失败");
        }

        // 保存验证码信息
        String code = (int) ((Math.random() * 9 + 1) * 100000) + "";

        // 发送验证码
        Boolean sendStatus = sendSmsCode(phone, code);
        if (!sendStatus) {
            return AjaxResult.error();
        }

        // 模拟发送成功后缓存验证码
        String verifyKey = Constants.USER_LOGIN_CODE + phone;

        redisService.setCacheObject(verifyKey, code, 5, TimeUnit.MINUTES);
        redisService.setCacheObject(frequency, "1", 1, TimeUnit.MINUTES);
//        ajax.put("smscode", code);
        return AjaxResult.success();
    }

    /**
     * 校验验证码
     *
     * @param key   手机号
     * @param value 密码
     * @throws CaptchaException
     */
    @Override
    public void checkCapcha(String key, String value) throws CaptchaException {
        if (StringUtils.isEmpty(value)) {
            throw new CaptchaException("验证码不能为空");
        }
        if (StringUtils.isEmpty(key)) {
            throw new CaptchaException("验证码已失效");
        }
        String verifyKey = Constants.USER_LOGIN_CODE + key;
        String captcha = redisService.getCacheObject(verifyKey);

        if (!value.equalsIgnoreCase(captcha)) {
            throw new CaptchaException("验证码错误");
        }
        // 验证成功，删除验证码
        redisService.deleteObject(verifyKey);
        // 同时生成假密码
        String uuid = IdUtils.simpleUUID();
        String encode = passwordEncoder.encode(uuid);

        String pKey = Constants.USER_LOGIN_PASSWORD + key;
        redisService.setCacheObject(pKey, uuid + ":" + encode, 3, TimeUnit.MINUTES);
    }

    private final Map<String, String> header = new HashMap<String, String>() {{
        put("Content-Type", "application/json");
    }};

    private Boolean sendSmsCode(String phone, String code) {
        String message = "【海客会平台】验证码：" + code + "(有效期为5分钟)，请勿泄露给他人，如非本人操作，请忽略此信息。";
        phone = "+86" + phone;
        StringBuilder sb = new StringBuilder();
        String stringSignTemp = sb.append("message=").append(message)
                .append("&")
                .append("phone=").append(phone)
                .append("&")
                .append("platformId=").append(smsPlatformId)
                .append("&")
                .append("key=").append(smsKey)
                .toString();
        String sign = MD5Utils.MD5Lower(stringSignTemp);
        SmsMessageVO vo = new SmsMessageVO();
        vo.setMessage(message);
        vo.setPhone(phone);
        vo.setPlatformId(smsPlatformId);
        vo.setSign(sign);
        String s = JSON.toJSONString(vo);
        log.info("发送验证码 ：{}", s);
        JSONObject jsonObject = HttpUtil.doPoststr(smsDomain + smsUrl, s, header);
        log.info("验证码相应：{}", jsonObject.toJSONString());
        if (DataUtils.isNotEmpty(jsonObject) && Objects.equals(jsonObject.getInteger("status"), 200)) {
            return true;
        }
        return false;
    }

    @Data
    static class SmsMessageVO {
        private String message; // 短信内容，必须包含"【海客会平台】"
        private String phone;// 带+86形式
        private String platformId;
        private String sign;
    }
}
